package com.sc.nft.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.entity.*;
import com.sc.nft.entity.dto.CopyrightAuctionRoundAdminDTO;
import com.sc.nft.entity.vo.CopyrightAuctionRoundAdminVO;
import com.sc.nft.entity.vo.CopyrightAuctionRoundUserListVO;
import com.sc.nft.enums.CopyrightCollectionStatusEnum;
import com.sc.nft.enums.RedisKeyEnum;
import com.sc.nft.enums.UserCollectionFreezingStatusEnum;
import com.sc.nft.enums.UserEquityPropsHoldingStatusEnum;
import com.sc.nft.exception.GlobalException;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.util.BigDecimalUtils;
import com.sc.nft.util.WeChatUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.swing.text.StyledEditorKit;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 版权拍卖轮次 服务实现类
 * </p>
 *
 * @author liGen
 * @since 2024-09-12
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CopyrightAuctionRoundServiceImpl implements CopyrightAuctionRoundService {


    private final CopyrightAuctionRoundDao copyrightAuctionRoundDao;
    private final CopyrightAuctionUserBiddingDao copyrightAuctionUserBiddingDao;
    private final CopyrightAuctionRecordService copyrightAuctionRecordService;
    private final UserEquityPropsService userEquityPropsService;
    private final CopyrightAuctionDao copyrightAuctionDao;
    private final CopyrightAuctionUserBiddingDetailDao copyrightAuctionUserBiddingDetailDao;
    private final CopyrightAuctionService copyrightAuctionService;
    private final NftRegionBindingService nftRegionBindingService;
    private final UserCollectionService userCollectionService;
    private final Redisson redisson;
    private final CopyrightAuctionConfigDao copyrightAuctionConfigDao;


    /**
     * 当前用户参与记录 轮次
     *
     * @param copyrightAuctionRecordId
     * @param mp
     * @return
     */
    @Override
    public List<CopyrightAuctionRoundUserListVO> copyrightAuctionRoundUserList(Long copyrightAuctionRecordId,Long userId) {
        return copyrightAuctionRoundDao.copyrightAuctionRoundUserList(copyrightAuctionRecordId,userId);
    }

    /**
     * 拍卖轮数
     *
     * @param copyrightAuctionRoundAdminDTO
     * @return
     */
    @Override
    public List<CopyrightAuctionRoundAdminVO> copyrightAuctionRoundAdminList(CopyrightAuctionRoundAdminDTO copyrightAuctionRoundAdminDTO) {
        return copyrightAuctionRoundDao.copyrightAuctionRoundAdminList(copyrightAuctionRoundAdminDTO.getCopyrightAuctionRecordId());
    }

    /**
     * 获取所有轮次
     *
     * @param copyrightAuctionRecordId 拍卖记录id
     * @return
     */
    @Override
    public List<CopyrightAuctionRound> getRoundList(Long copyrightAuctionRecordId) {
        return copyrightAuctionRoundDao.getRoundList(copyrightAuctionRecordId);
    }




    /**
     * 拍卖处理
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void auctionDisposal() {
        //线程睡2秒等待一下
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        RLock lock = redisson.getLock(RedisKeyEnum.SECOND_BIDDING_RESULTS_LOCK.getKey());
        try {
            boolean res = lock.tryLock(3, TimeUnit.SECONDS);
            if (!res) {
                throw new GlobalException("拍卖处理中！！！！");
            }
            CopyrightAuctionConfig auctionConfig = copyrightAuctionConfigDao.getNewOne();
            if (Objects.isNull(auctionConfig)) {
                throw new GlobalRunTimeException("二级拍卖处理拍卖配置为空");
            }
            Date now = new Date();
            // 获取已经开始并且未生成拍卖结果的记录
            List<CopyrightAuctionRecord> notHaveResultList = copyrightAuctionRecordService.getNotHaveResultList(now);
            if (CollectionUtils.isEmpty(notHaveResultList)) {
                return;
            }
            // 遍历
            for (CopyrightAuctionRecord copyrightAuctionRecord : notHaveResultList) {
                CopyrightAuction copyrightAuction = copyrightAuctionDao.getById(copyrightAuctionRecord.getCopyrightAuctionId());
                // 是否是最后一轮
                Boolean theLastRound = Boolean.FALSE;
                // 当前时间下一轮次
                CopyrightAuctionRound nextRound = null;
                // 当前时间上一轮次
                CopyrightAuctionRound lastRound = null;
                //获取拍卖记录所有轮次
                List<CopyrightAuctionRound> roundList = getRoundList(copyrightAuctionRecord.getId());
                for (int i = 0; i < roundList.size(); i++) {
                    CopyrightAuctionRound copyrightAuctionRound = roundList.get(i);
                    if (copyrightAuctionRound.getRoundEndTime().before(now) && !copyrightAuctionRound.getFinish()) {
                        // 上一轮
                        lastRound = copyrightAuctionRound;
                        if (i == roundList.size() - 1) {
                            theLastRound = Boolean.TRUE;
                        } else {
                            nextRound = roundList.get(i + 1);
                        }
                        break;
                    }
                }
                if (Objects.isNull(lastRound)) {
                    // 没有需要处理的轮数
                    continue;
                }
                // 获取上一轮出价
                List<CopyrightAuctionUserBidding> copyrightAuctionUserBiddingList = copyrightAuctionUserBiddingDao.getList(lastRound.getId(), lastRound.getId());
                // 判断是否为最后一轮结束
                if (theLastRound) {
                    // 最后一轮 处理 TODO
                    if (CollectionUtils.isEmpty(copyrightAuctionUserBiddingList)) {
                        // 最后一轮依然没人出价 流拍
                        copyrightAuctionRecordService.updateHaveResult(copyrightAuctionRecord.getId(), Boolean.TRUE);
                        copyrightAuctionRoundDao.updateRoundHighestPrice(lastRound.getId(), 0);
                        // 版权权益时间添加
                        nftRegionBindingService.updateNftEffectiveTime(copyrightAuction.getCollectionId());
                        copyrightAuctionDao.updateStartPrice(copyrightAuction.getId(),copyrightAuctionRecord.getStartPrice());
                        userCollectionService.updateFreezingStatusById(copyrightAuctionRecord.getUserCollectionId(), UserCollectionFreezingStatusEnum.NORMAL);
                    } else {
                        // 移除最高价
                        CopyrightAuctionUserBidding max = copyrightAuctionUserBiddingList.remove(0);
                        // 最高价 单独处理
                        List<CopyrightAuctionUserBiddingDetail> maxCopyrightAuctionUserBiddingDetailDaoList =
                                copyrightAuctionUserBiddingDetailDao.getList(copyrightAuctionRecord.getId(), Lists.newArrayList(max.getId()));
                        List<Long> maxUserRelationIds = maxCopyrightAuctionUserBiddingDetailDaoList.stream().
                                map(copyrightAuctionUserBiddingDetail -> copyrightAuctionUserBiddingDetail.getRelationId()).collect(Collectors.toList());
                        // 中标状态修改
                        copyrightAuctionUserBiddingDao.biddingProcess(max.getId(), Boolean.TRUE, Boolean.TRUE, CopyrightCollectionStatusEnum.AUCTION_IS_SUCCESSFUL);
                        // 最后一轮最高价添加
                        copyrightAuctionRoundDao.updateRoundHighestPrice(lastRound.getId(), max.getBiddingNum());
                        copyrightAuctionRecordService.updateHaveResult(copyrightAuctionRecord.getId(), Boolean.TRUE);

                        // 处理非最高价
                        List<Long> biddingIds = copyrightAuctionUserBiddingList.stream().map(copyrightAuctionUserBidding -> copyrightAuctionUserBidding.getId()).collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(biddingIds)){
                            // 释放
                            Assert.isTrue(copyrightAuctionUserBiddingDao.updateStatus(biddingIds, CopyrightCollectionStatusEnum.HAS_RELEASED,Boolean.FALSE), () -> new GlobalRunTimeException(ErrorCode.COPYRIGHT_AUCTION_BID_STATUS_CHANGE_FAILED));
                            // 用户道具转正常
                            List<CopyrightAuctionUserBiddingDetail> copyrightAuctionUserBiddingDetailDaoList = copyrightAuctionUserBiddingDetailDao.getList(copyrightAuctionRecord.getId(), biddingIds);
                            List<Long> userRelationIds = copyrightAuctionUserBiddingDetailDaoList.stream().map(copyrightAuctionUserBiddingDetail -> copyrightAuctionUserBiddingDetail.getRelationId()).collect(Collectors.toList());
                            Assert.isTrue(userEquityPropsService.updateHoldStatusBatchById(userRelationIds, UserEquityPropsHoldingStatusEnum.NORMAL, UserEquityPropsHoldingStatusEnum.AUCTION_LOCK), () -> new GlobalRunTimeException("用户道具转正常失败"));
                        }

                        // 拍卖结果处理
                        // 获取上几轮的最高价
                        List<CopyrightAuctionUserBidding> highestList = copyrightAuctionUserBiddingDao.getIsHighestList(copyrightAuctionRecord.getId());
                        // 每轮对应的
                        Map<Long, CopyrightAuctionUserBidding> needMap = highestList.stream().collect(Collectors.toMap(CopyrightAuctionUserBidding::getCopyrightAuctionRoundId, copyrightAuctionUserBidding -> copyrightAuctionUserBidding));
                        // 需要给各个人的map
                        Map<Long, Integer> giveMap = new HashMap<>();
                        Integer giveTotal = 0;
                        //最后一轮才有人出价
                        Boolean lastRoundHavePrice = Boolean.TRUE;
                        for (int i = 0; i < roundList.size(); i++) {
                            if (i != roundList.size() - 1) {
                                // 排除最后一轮 看每一轮给多少
                                CopyrightAuctionRound copyrightAuctionRound = roundList.get(i);
                                // 每轮最高出价
                                Integer roundHighestPrice = copyrightAuctionRound.getRoundHighestPrice();
                                if (roundHighestPrice != 0) {
                                    lastRoundHavePrice = Boolean.FALSE;
                                    // 对应的出价
                                    CopyrightAuctionUserBidding copyrightAuctionUserBidding = needMap.get(copyrightAuctionRound.getId());
                                    // 有人出价才处理
                                    if (!giveMap.containsKey(copyrightAuctionRecord.getUserId())) {
                                        // 藏品所有者 就给一次
                                        Integer userStartPrice = copyrightAuctionRecord.getStartPrice();
                                        Integer needGive = BigDecimalUtils.divide((roundHighestPrice - userStartPrice), 2, 0, RoundingMode.DOWN).intValue();
                                        giveMap.put(copyrightAuctionRecord.getUserId(), needGive + userStartPrice);
                                        giveTotal = giveTotal + userStartPrice + needGive;
                                    }
                                    // 再给每一轮的最高出价者
                                    CopyrightAuctionRound next = roundList.get(i + 1);
                                    if (i + 1 == roundList.size() - 1) {
                                        next.setRoundHighestPrice(max.getBiddingNum());
                                    }
                                    Integer nextRoundHighestPrice = next.getRoundHighestPrice();
                                    Integer needGive = BigDecimalUtils.divide((nextRoundHighestPrice - roundHighestPrice), 2, 0, RoundingMode.DOWN).intValue();
                                    if (giveMap.containsKey(copyrightAuctionUserBidding.getUserId())) {
                                        Integer integer = giveMap.get(copyrightAuctionUserBidding.getUserId());
                                        giveMap.replace(copyrightAuctionUserBidding.getUserId(), needGive + integer);
                                    } else {
                                        giveMap.put(copyrightAuctionUserBidding.getUserId(), needGive);
                                    }
                                    giveTotal = giveTotal + needGive;
                                }
                            }else {
                                if (lastRoundHavePrice) {
                                    //给藏品拥有者发道具
                                    CopyrightAuctionRound copyrightAuctionRound = roundList.get(i);
                                    CopyrightAuctionUserBidding copyrightAuctionUserBidding = copyrightAuctionUserBiddingDao.getHighByRecordIdAndRoundId(copyrightAuctionRecord.getId(),copyrightAuctionRound.getId());
                                    Integer needGive = BigDecimalUtils.divide((copyrightAuctionUserBidding.getBiddingNum() - copyrightAuctionRecord.getStartPrice()), 2, 0, RoundingMode.DOWN).intValue();
                                    giveMap.put(copyrightAuctionRecord.getUserId(), needGive + copyrightAuctionRecord.getStartPrice());
                                    giveTotal = giveTotal + copyrightAuctionRecord.getStartPrice() + needGive;
                                }
                            }
                        }
                        // 手续费给平台
                        giveMap.put(0L, max.getBiddingNum() - giveTotal);
                        // 处理道具
                        userEquityPropsService.disposalOfAuctionItems(maxUserRelationIds, giveMap, copyrightAuctionRecord.getId(), copyrightAuction.getId(), copyrightAuctionRecord.getId());
                        // 处理藏品
                        userCollectionService.successfulAuction(copyrightAuctionRecord.getUserCollectionId(), max.getUserId());
                        copyrightAuctionDao.updateStartPrice(copyrightAuction.getId(),max.getBiddingNum());
                        nftRegionBindingService.updateNftEffectiveTime(copyrightAuction.getCollectionId());
                    }
                } else {
                    // 不是最后一轮
                    if (CollectionUtils.isEmpty(copyrightAuctionUserBiddingList)) {
                        // 无人出价 修改轮次最高价
                        // 更新
                        copyrightAuctionRoundDao.updateRoundHighestPrice(lastRound.getId(), 0);
                    } else {
                        // 处理报价
                        // 移除最高价
                        CopyrightAuctionUserBidding max = copyrightAuctionUserBiddingList.remove(0);
                        // 最高价 单独处理
                        List<CopyrightAuctionUserBiddingDetail> maxCopyrightAuctionUserBiddingDetailDaoList =
                                copyrightAuctionUserBiddingDetailDao.getList(copyrightAuctionRecord.getId(), Lists.newArrayList(max.getId()));
                        List<Long> maxUserRelationIds = maxCopyrightAuctionUserBiddingDetailDaoList.stream().
                                map(copyrightAuctionUserBiddingDetail -> copyrightAuctionUserBiddingDetail.getRelationId()).collect(Collectors.toList());
                        // 将当前最高价 延续到下一轮
                        copyrightAuctionService.generateNextStartPrice(lastRound, nextRound, max.getBiddingNum(), max.getUserId(), maxUserRelationIds);
                        // 最高价处理
                        copyrightAuctionUserBiddingDao.updateRoundHighest(max.getId(), Boolean.TRUE);
                        copyrightAuctionRoundDao.updateRoundHighestPrice(lastRound.getId(), max.getBiddingNum());

                        // 处理非最高价
                        List<Long> biddingIds = copyrightAuctionUserBiddingList.stream().map(copyrightAuctionUserBidding -> copyrightAuctionUserBidding.getId()).collect(Collectors.toList());
                        if (!CollectionUtils.isEmpty(biddingIds)){
                            // 释放
                            Assert.isTrue(copyrightAuctionUserBiddingDao.updateStatus(biddingIds, CopyrightCollectionStatusEnum.HAS_RELEASED,null), () -> new GlobalRunTimeException(ErrorCode.COPYRIGHT_AUCTION_BID_STATUS_CHANGE_FAILED));
                            // 用户道具转正常
                            List<CopyrightAuctionUserBiddingDetail> copyrightAuctionUserBiddingDetailDaoList = copyrightAuctionUserBiddingDetailDao.getList(copyrightAuctionRecord.getId(), biddingIds);
                            List<Long> userRelationIds = copyrightAuctionUserBiddingDetailDaoList.stream().map(copyrightAuctionUserBiddingDetail -> copyrightAuctionUserBiddingDetail.getRelationId()).collect(Collectors.toList());
                            Assert.isTrue(userEquityPropsService.updateHoldStatusBatchById(userRelationIds, UserEquityPropsHoldingStatusEnum.NORMAL, UserEquityPropsHoldingStatusEnum.AUCTION_LOCK), () -> new GlobalRunTimeException("用户道具转正常失败"));
                        }
                    }
                }
            }
        } catch (Exception e) {
            WeChatUtil.sendLiGenWeChatMessage(StrUtil.format("拍卖处理失败 ,异常:{}", e.getMessage()));
            log.error("拍卖处理失败,异常:{}", e.getMessage());
            throw new GlobalRunTimeException(e.getMessage());
        } finally {
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}
